package cn.roadtrip.mtravelbusinessmodule.bs.shopproduct;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.digest.MD5;
import cn.roadtrip.mtravelbusinessmodule.dao.bs.PortalProductMapper;
import cn.roadtrip.mtravelbusinessmodule.dao.bs.vpo.PortalProductItem;
import cn.roadtrip.mtravelbusinessmodule.dao.order.ShopOrderMapper;
import cn.roadtrip.mtravelbusinessmodule.dao.order.po.ShopOrder;
import cn.roadtrip.mtravelbusinessmodule.sql.couple.tables.CoupleShopOrder;
import cn.roadtrip.mtravelbusinessmodule.sql.couple.tables.records.CoupleShopOrderRecord;
import cn.roadtrip.mtravelbusinessmodule.sql.couple.tables.records.CoupleShopPdtRecord;
import cn.roadtrip.mtravelbusinessmodule.sql.dto.CoupleShopOrderDTO;
import cn.roadtrip.umysqlmodule.transaction.TransactionRollback;
import cn.roadtrip.utilmodule.util.DataBean;
import com.github.yitter.idgen.YitIdHelper;
import lombok.*;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.jooq.DSLContext;
import org.jooq.impl.DSL;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import static cn.roadtrip.mtravelbusinessmodule.sql.couple.Tables.COUPLE_SHOP_ORDER;
import static cn.roadtrip.mtravelbusinessmodule.sql.couple.Tables.COUPLE_SHOP_PDT;

/**
 * 店铺商品操作
 */
@Component
public class ShopProductOrderImpl {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Autowired
    private TransactionRollback transactionRollback;
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private DSLContext dslContext;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 商品交易订单前缀
     */
    public static final String PRE_PRODUCT_ORDER_PREFIX = "PRE_PRODUCT_TRADE_STATS:";
    /**
     * 临时核销码redis前缀
     */
    public static final String DEAL_PRODUCT_ORDER_CODE_PREFIX = "DEAL_PRODUCT_CODE_STATS:";

    /**
     *
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @EqualsAndHashCode
    public static class Model_productPrePay {
        private String userId;//用户ID
        private String prtId;//商品ID
        private Integer buyNum;//购买数量
    }


    /**
     * 商品预支付，返回订单号，以及签名
     *
     * @param model
     * @return
     */
    public DataBean productPrePay(Model_productPrePay model) {
        if (model.getBuyNum() == null || model.getBuyNum() < 1) {
            model.setBuyNum(1);
        }
        return transactionRollback.transaction(
                () -> {
                    try (SqlSession sql = sqlSessionFactory.openSession(true)) {
                        String tradeId = "LT" + YitIdHelper.nextId();
/**
 * 待支付	B02A01A01
 * 已支付	B02A01A02
 * 待核销	B02A01A03
 */
//根据ID查询产品
                        PortalProductMapper productMapper = sql.getMapper(PortalProductMapper.class);
                        PortalProductItem product = productMapper.getProductById(model.getPrtId());
                        if (product == null) {
                            return DataBean.err("product-is-null", "商品不存在");
                        }

                        //保存预支付订单
                        ShopOrderMapper orderMapper = sql.getMapper(ShopOrderMapper.class);
                        orderMapper.insert(
                                new ShopOrder(
                                        tradeId
                                        , model.getUserId() + ""
                                        , new Date(System.currentTimeMillis())
                                        , model.getUserId() + ""
                                        , new Date(System.currentTimeMillis())
                                        , ""
                                        , "待支付"
                                        , product.getPid()
                                        , BigDecimal.valueOf(product.getPrice() * model.getBuyNum())
                                        , model.getUserId()
                                        , "待核销"
                                        , ""
                                        , new Date(product.getExpiration() == null ? DateUtil.parse("2099-12-31").getTime() : product.getExpiration().getTime())
                                        , null,
                                        model.getBuyNum()
                                )
                        );
                        //redis保存商品订单交易信息
                        boolean exist = !stringRedisTemplate.opsForValue().setIfAbsent(PRE_PRODUCT_ORDER_PREFIX + tradeId, "待付款", 24l, TimeUnit.HOURS);
                        if (exist) {
                            throw new Exception("不许重复交易");
                        }
                        sql.commit();
                        DataBean db = DataBean.suc(tradeId, 1, "suc", "操作成功");
                        return db;
                    }
                },
                (e) -> {
                    e.printStackTrace();
                    return DataBean.err("trans-err", e.getMessage());
                }
        );
    }


    /**
     *
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @EqualsAndHashCode
    public static class Model_payProductOrder {
        private String tradeId;
        private String userId;
    }

    /**
     * 商品订单付款操作--api操作
     *
     * @param model
     * @return
     */
    public DataBean payProductOrderFromAPI(
            Model_payProductOrder model
    ) {
        if (model.getTradeId() == null || model.getTradeId().trim().equals("")) {
            return DataBean.err("trade-id-null", "交易id不能为空");
        }
        if (model.getUserId() == null || model.getUserId().trim().equals("")) {
            return DataBean.err("user-id-null", "用户ID不能为空");
        }
        //查询订单是否存在
        String orderStats = stringRedisTemplate.opsForValue().get(PRE_PRODUCT_ORDER_PREFIX + model.getTradeId());
        if (orderStats == null) {
            return DataBean.err("order-not-exist", "订单不存在");
        }
        if (!orderStats.equals("已付款")) {
            return DataBean.err("order-status-error", "订单还未付款");
        } else if (orderStats.equals("已付款")) {
            return DataBean.suc(true, 1, "suc", "付款成功");
        }
        //付款操作
        DataBean db = null;
        try {
            db = dslContext.transactionResult(ctx -> {
                //修改订单状态
                int i = dslContext.update(CoupleShopOrder.COUPLE_SHOP_ORDER)
                        .set(CoupleShopOrder.COUPLE_SHOP_ORDER.ORDER_STATUS, "已付款")
                        .where(
                                CoupleShopOrder.COUPLE_SHOP_ORDER.ID.eq(model.getTradeId())
                                        .and(
                                                CoupleShopOrder.COUPLE_SHOP_ORDER.USER_ID.eq(model.getUserId())
                                        )
                        )
                        .execute();
                if (i <= 0) {
                    throw new RuntimeException("订单编号错误");
                }
                dslContext.commit();
                return DataBean.suc(true, 1, "suc", "付款成功");
            });
        } catch (Exception e) {
            e.printStackTrace();
            return DataBean.err("err", e.getMessage());
        }

        return db;
    }


    /**
     * 商品订单付款操作--回调操作
     *
     * @param model
     * @return
     */
    public DataBean payProductOrderFromCallBack(
            Model_payProductOrder model
    ) {
        if (model.getTradeId() == null || model.getTradeId().trim().equals("")) {
            return DataBean.err("trade-id-null", "交易id不能为空");
        }
        //查询订单是否存在
        String orderStats = stringRedisTemplate.opsForValue().get(PRE_PRODUCT_ORDER_PREFIX + model.getTradeId());
        if (orderStats == null) {
            return DataBean.err("order-not-exist", "订单不存在");
        }
        if (!orderStats.equals("待付款")) {
            return DataBean.err("order-status-error", "订单状态错误");
        }
        //付款操作
        DataBean db = null;
        try {
            db = dslContext.transactionResult(ctx -> {
                //修改订单状态
                int i = dslContext.update(CoupleShopOrder.COUPLE_SHOP_ORDER)
                        .set(CoupleShopOrder.COUPLE_SHOP_ORDER.ORDER_STATUS, "已付款")
                        .where(CoupleShopOrder.COUPLE_SHOP_ORDER.ID.eq(model.getTradeId()))
                        .execute();
                if (i <= 0) {
                    throw new RuntimeException("订单编号错误");
                }
                stringRedisTemplate.opsForValue().setIfPresent(PRE_PRODUCT_ORDER_PREFIX + model.getTradeId(), "已付款", 24l, TimeUnit.HOURS);
                dslContext.commit();
                return DataBean.suc(true, 1, "suc", "付款成功");
            });
        } catch (Exception e) {
            e.printStackTrace();
            return DataBean.err("err", e.getMessage());
        }
        return db;
    }


    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public static class Model_queryUserShopProductOrderList {
        private String userId;
        private String stats;
        private Integer cpage;
        private Integer pagesize;
    }

    /**
     * 查询用户的商品订单
     *
     * @param model
     * @return
     */
    public /*DataBean<Result<CoupleShopOrderRecord>>*/ DataBean<java.util.List<CoupleShopOrderDTO>> queryUserShopProductOrderList(Model_queryUserShopProductOrderList model) {
        int count = dslContext.selectCount().from(CoupleShopOrder.COUPLE_SHOP_ORDER).where(
                CoupleShopOrder.COUPLE_SHOP_ORDER.USER_ID.eq(model.getUserId())
                        .and(
                                (model.getStats() == null || model.getStats().trim().equals("")) ? DSL.noCondition() : CoupleShopOrder.COUPLE_SHOP_ORDER.ORDER_STATUS.eq(model.getStats())
                        )
        ).fetchOne().value1();
        if (count == 0) {
            return DataBean.sucEmpty();
        }
//
//        Result<CoupleShopOrderRecord> list = null;
//        try {
//            list = dslContext.selectFrom(CoupleShopOrder.COUPLE_SHOP_ORDER)
//                    .where(
//                            CoupleShopOrder.COUPLE_SHOP_ORDER.USER_ID.eq(model.getUserId())
//                                    .and(
//                                            (model.getStats() == null || model.getStats().trim().equals("")) ? DSL.noCondition() : CoupleShopOrder.COUPLE_SHOP_ORDER.ORDER_STATUS.eq(model.getStats())
//                                    )
//                    ).orderBy(CoupleShopOrder.COUPLE_SHOP_ORDER.CREATE_TIME.desc())
//                    .limit((model.getCpage() * model.getPagesize()), model.getPagesize())
//                    .fetch();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }


        java.util.List<CoupleShopOrderDTO> list = null;
        try {
            list = dslContext.selectFrom(CoupleShopOrder.COUPLE_SHOP_ORDER)
                    .where(
                            CoupleShopOrder.COUPLE_SHOP_ORDER.USER_ID.eq(model.getUserId())
                                    .and(
                                            (model.getStats() == null || model.getStats().trim().equals("")) ? DSL.noCondition() : CoupleShopOrder.COUPLE_SHOP_ORDER.ORDER_STATUS.eq(model.getStats())
                                    )
                    ).orderBy(CoupleShopOrder.COUPLE_SHOP_ORDER.CREATE_TIME.desc())
                    .limit((model.getCpage() * model.getPagesize()), model.getPagesize())
                    .fetch().into(CoupleShopOrderDTO.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return DataBean.suc(list, count, "suc", "操作成功");
    }

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public static class Model_createProductDealCode {
        private String userId;
        private String productId;
        private String orderId;
    }

    public CoupleShopOrderRecord _userPayedProductById(
            String userId,
            String orderId,
            String productId
    ) {
        CoupleShopOrderRecord r = dslContext.selectFrom(COUPLE_SHOP_ORDER)
                .where(
                        COUPLE_SHOP_ORDER.USER_ID.eq(userId)
                                .and(COUPLE_SHOP_ORDER.PDT_ID.eq(productId))
                                .and(COUPLE_SHOP_ORDER.ORDER_STATUS.eq("已付款"))
                                .and(COUPLE_SHOP_ORDER.ID.eq(orderId))
                ).fetchOne();
        return r;
    }

    /**
     * 产品是否已经到期
     *
     * @param productId
     * @return
     */
    public boolean _productIsExpire(
            String productId
    ) throws Exception {
        CoupleShopPdtRecord pdt = dslContext.selectFrom(COUPLE_SHOP_PDT)
                .where(
                        COUPLE_SHOP_PDT.ID.eq(productId)
                ).fetchOne();
        if (pdt == null) {
            throw new Exception("产品不存在");
        }
        if (pdt.getExpirationTime().isBefore(LocalDateTime.now())) {
            return true;
        } else {
            return false;

        }
    }

    /**
     * 创建产品核临时销码
     *
     * @param model
     * @return
     */
    public DataBean createProductDealCode(Model_createProductDealCode model) {
        CoupleShopOrderRecord shopOrderRecord = _userPayedProductById(
                model.getUserId(),
                model.getOrderId(),
                model.getProductId()
        );
        //检查用户是否已购买这个产品
        if (shopOrderRecord == null) {
            return DataBean.err("none-order", "用户未购买产品");
        }
        //检查产品是否已经被核销过了
        if (shopOrderRecord.getChargeOffStatus().equals("已核销")) {
            return DataBean.err("charge-off", "产品已经核销过了");
        }
        //检查产品是否已经到期
        try {
            if (_productIsExpire(model.getProductId())) {
                return DataBean.err("expire", "产品已经到期");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return DataBean.err("product-none", e.getMessage());
        }
        //创建核销码
        String code = MD5.create().digestHex("" + System.currentTimeMillis()) + ":" + model.getUserId();
        stringRedisTemplate.opsForValue().set(
                DEAL_PRODUCT_ORDER_CODE_PREFIX + code,
                shopOrderRecord.getId(),
                5,
                TimeUnit.MINUTES
        );
        return DataBean.suc(code, 1, "suc", "操作成功");
    }


    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode
    public static class Model_deaProductOrder {
        private String code;
        private String dealUserId;//核销员ID
    }

    /**
     * 核销产品订单
     *
     * @param model
     * @return
     */
    public DataBean dealProductOrder(
            Model_deaProductOrder model
    ) {
        try {
            return dslContext.transactionResult(ctx -> {
                String orderId = stringRedisTemplate.opsForValue().get(DEAL_PRODUCT_ORDER_CODE_PREFIX + model.getCode());
                if (orderId == null) {
                    return DataBean.err("code-none", "核销码错误");
                }
                CoupleShopOrderRecord order = dslContext.selectFrom(COUPLE_SHOP_ORDER)
                        .where(
                                COUPLE_SHOP_ORDER.ID.eq(orderId)
                        ).fetchOne();
                if (order == null) {
                    return DataBean.err("order-none", "订单不存在");
                }
                if (order.getChargeOffStatus().equals("已核销")) {
                    return DataBean.err("charge-off", "订单已核销");
                }
                order.setChargeOffTime(LocalDateTime.now());
                order.setChargeOffUser(model.getDealUserId());
                order.setChargeOffStatus("已核销");
                order.update();
                dslContext.commit();
                stringRedisTemplate.opsForValue().getAndDelete(DEAL_PRODUCT_ORDER_CODE_PREFIX + model.getCode());
                return DataBean.suc(true, 1, "suc", "操作成功");
            });
        } catch (Exception e) {
            e.printStackTrace();
            return DataBean.err("trans-err", e.getMessage());
        }
    }
}
